/**
 *******************************************************************************
 * @file  com.c
 * @brief This file provides firmware functions to manage the Communication
 *        Device driver.
 @verbatim
   Change Logs:
   Date             Author          Notes
   2019-06-26       Yangjp          First version
 @endverbatim
 *******************************************************************************
 * Copyright (C) 2016, Huada Semiconductor Co., Ltd. All rights reserved.
 *
 * This software is owned and published by:
 * Huada Semiconductor Co., Ltd. ("HDSC").
 *
 * BY DOWNLOADING, INSTALLING OR USING THIS SOFTWARE, YOU AGREE TO BE BOUND
 * BY ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT.
 *
 * This software contains source code for use with HDSC
 * components. This software is licensed by HDSC to be adapted only
 * for use in systems utilizing HDSC components. HDSC shall not be
 * responsible for misuse or illegal use of this software for devices not
 * supported herein. HDSC is providing this software "AS IS" and will
 * not be responsible for issues arising from incorrect user implementation
 * of the software.
 *
 * Disclaimer:
 * HDSC MAKES NO WARRANTY, EXPRESS OR IMPLIED, ARISING BY LAW OR OTHERWISE,
 * REGARDING THE SOFTWARE (INCLUDING ANY ACCOMPANYING WRITTEN MATERIALS),
 * ITS PERFORMANCE OR SUITABILITY FOR YOUR INTENDED USE, INCLUDING,
 * WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, THE IMPLIED
 * WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE OR USE, AND THE IMPLIED
 * WARRANTY OF NONINFRINGEMENT.
 * HDSC SHALL HAVE NO LIABILITY (WHETHER IN CONTRACT, WARRANTY, TORT,
 * NEGLIGENCE OR OTHERWISE) FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT
 * LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION,
 * LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING FROM USE OR
 * INABILITY TO USE THE SOFTWARE, INCLUDING, WITHOUT LIMITATION, ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOSS OF DATA,
 * SAVINGS OR PROFITS,
 * EVEN IF Disclaimer HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * YOU ASSUME ALL RESPONSIBILITIES FOR SELECTION OF THE SOFTWARE TO ACHIEVE YOUR
 * INTENDED RESULTS, AND FOR THE INSTALLATION OF, USE OF, AND RESULTS OBTAINED
 * FROM, THE SOFTWARE.
 *
 * This software may be replicated in part or whole for the licensed use,
 * with the restriction that this Disclaimer and Copyright notice must be
 * included with each copy of this software, whether used in part or whole,
 * at all times.
 *******************************************************************************
 */

/*******************************************************************************
 * Include files
 ******************************************************************************/
#include "com.h"
#include "basic.h"

/**
 * @addtogroup HC32_Boot
 * @{
 */

/**
 * @defgroup COM COM
 * @{
 */

/*******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/

/*******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/
/**
 * @defgroup COM_Local_Macros COM Local Macros
 * @{
 */

/* USART register bit definition */
#if defined(HC32F460)
    #define USART_DR_RDR_POS            (16U)

    #define USART_SR_PE                 (0x00000001UL)
    #define USART_SR_FE                 (0x00000002UL)
    #define USART_SR_ORE                (0x00000008UL)
    #define USART_SR_RXNE               (0x00000020UL)
    #define USART_SR_TC                 (0x00000040UL)

    #define USART_CR1_RE                (0x00000004UL)
    #define USART_CR1_TE                (0x00000008UL)
    #define USART_CR1_PS                (0x00000200UL)
    #define USART_CR1_PCE               (0x00000400UL)
    #define USART_CR1_M                 (0x00001000UL)
    #define USART_CR1_OVER8             (0x00008000UL)
    #define USART_CR1_CPE               (0x00010000UL)
    #define USART_CR1_CFE               (0x00020000UL)
    #define USART_CR1_CORE              (0x00080000UL)
    #define USART_CR1_CRTOF             (0x00100000UL)
    #define USART_CR1_MS                (0x01000000UL)
    #define USART_CR1_ML                (0x10000000UL)
    #define USART_CR1_FBME              (0x20000000UL)
    #define USART_CR1_NFE               (0x40000000UL)
    #define USART_CR1_SBS               (0x80000000UL)
#endif

/* USART mask definition */
#define USART_ERROR_FLAG_MASK           (USART_SR_PE   | USART_SR_FE   | USART_SR_ORE)
#define USART_CLEAN_FLAG_MASK           (USART_CR1_CPE | USART_CR1_CFE | USART_CR1_CORE)

/* Baud rate definition */
#if defined(HC32F460)
    #if (MODEM_USART_BAUD_RATE == BR_115200)
        #define USART_BRR_CONFIG        ((0x5AUL << 8U) | 0x7FUL)
    #elif (MODEM_USART_BAUD_RATE == BR_256000)
        #define USART_BRR_CONFIG        ((0x28UL << 8U) | 0x7FUL)
    #elif (MODEM_USART_BAUD_RATE == BR_512000)
        #define USART_BRR_CONFIG        ((0x13UL << 8U) | 0x79UL)
    #elif (MODEM_USART_BAUD_RATE == BR_921600)
        #define USART_BRR_CONFIG        ((0x0AUL << 8U) | 0x77UL)
    #elif (MODEM_USART_BAUD_RATE == BR_1228800)
        #define USART_BRR_CONFIG        ((0x07UL << 8U) | 0x6FUL)
    #endif
#elif defined(HC32F120) || defined(HC32M120) || defined(HC32F160)
    #if (MODEM_USART_BAUD_RATE == BR_115200)
        #define USART_BRR_CONFIG        (0x33UL << 8U)
    #elif (MODEM_USART_BAUD_RATE == BR_256000)
        #define USART_BRR_CONFIG        (0x16UL << 8U)
    #elif (MODEM_USART_BAUD_RATE == BR_512000)
        #define USART_BRR_CONFIG        (0x0BUL << 8U)
    #elif (MODEM_USART_BAUD_RATE == BR_921600)
        #define USART_BRR_CONFIG        (0x06UL << 8U)
    #elif (MODEM_USART_BAUD_RATE == BR_1228800)
        #define USART_BRR_CONFIG        (0x04UL << 8U)
    #endif
#elif defined(HC32F4A0)
    #if (MODEM_USART_BAUD_RATE == BR_115200)
        #define USART_BRR_CONFIG        (0x000081FFUL)
    #elif (MODEM_USART_BAUD_RATE == BR_256000)
        #define USART_BRR_CONFIG        (0x000039FDUL)
    #elif (MODEM_USART_BAUD_RATE == BR_512000)
        #define USART_BRR_CONFIG        (0x00001CFDUL)
    #elif (MODEM_USART_BAUD_RATE == BR_921600)
        #define USART_BRR_CONFIG        (0x00000FFBUL)
    #elif (MODEM_USART_BAUD_RATE == BR_1228800)
        #define USART_BRR_CONFIG        (0x00000BFBUL)
    #endif
#elif defined(HC32M423)
    #if (MODEM_USART_BAUD_RATE == BR_115200)
        #define USART_BRR_CONFIG        (0x56UL << 8U)
    #elif (MODEM_USART_BAUD_RATE == BR_256000)
        #define USART_BRR_CONFIG        (0x26UL << 8U)
    #elif (MODEM_USART_BAUD_RATE == BR_512000)
        #define USART_BRR_CONFIG        (0x13UL << 8U)
    #elif (MODEM_USART_BAUD_RATE == BR_921600)
        #define USART_BRR_CONFIG        (0x0AUL << 8U)
    #elif (MODEM_USART_BAUD_RATE == BR_1228800)
        #define USART_BRR_CONFIG        (0x07UL << 8U)
    #endif
#endif

/**
 * @}
 */

/*******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/

/*******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/

/*******************************************************************************
 * Local variable definitions ('static')
 ******************************************************************************/

/*******************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/
/**
 * @defgroup COM_Global_Functions COM Global Functions
 * @{
 */

/**
 * @brief  USART get receive status.
 * @param  None
 * @retval An en_result_t enumeration value:
 *           - Ok: Data was acceptable
 *           - ErrorNotReady: Data was unacceptable
 */
static en_result_t USART_GetRecvSta(void)
{
    if (0UL != READ_BIT(MODEM_USART->SR, USART_ERROR_FLAG_MASK))
    {
        /* Clear the RX error */
        SET_BIT(MODEM_USART->CR1, USART_CLEAN_FLAG_MASK);
    }

    /* Only Receive done set return OK */
    if (USART_SR_RXNE == READ_BIT(MODEM_USART->SR, USART_SR_RXNE))
    {
        return Ok;
    }

    return ErrorNotReady;
}

/**
 * @brief  USART send byte.
 * @param  [in] u8TxData                Send data.
 * @retval None
 */
static void USART_SendByte(uint8_t u8TxData)
{
    WRITE_REG(MODEM_USART->DR, u8TxData);
    while (USART_SR_TC != READ_BIT(MODEM_USART->SR, USART_SR_TC))
    {
    }
}

/**
 * @brief  USART receive byte.
 * @param  [out] u8RxData               Pointer to the data to be received.
 * @retval An en_result_t enumeration value:
 *           - Ok: Receive data finished
 *           - Error: Don't receive data
 */
static en_result_t USART_RecvByte(uint8_t *u8RxData)
{
    if (Ok == USART_GetRecvSta())
    {
        *u8RxData = (uint8_t)(READ_REG(MODEM_USART->DR) >> USART_DR_RDR_POS);
        return Ok;
    }

    return Error;
}

/**
 * @brief  COM De-Initialize
 * @param  None
 * @retval None
 */
void COM_DeInit(void)
{
#if defined(HC32F460)
    /* USART Port configure */
    CLEAR_BIT(M4_PORT->MODEM_USART_TX, PORT_PFSR_FSEL);
    CLEAR_BIT(M4_PORT->MODEM_USART_RX, PORT_PFSR_FSEL);

    /* USART configure */
    WRITE_REG(MODEM_USART->CR1, 0x80000000UL);
    WRITE_REG(MODEM_USART->DR,  0x01FFUL);
    WRITE_REG(MODEM_USART->BRR, 0xFFFFUL);
    /* Disable USART Clock. */
    SET_BIT(M4_MSTP->FCG1, MODEM_USART_CLK);
#elif defined(HC32F120) || defined(HC32M120)
    /* USART Port configure */
    CLEAR_BIT(M0P_PORT->MODEM_USART_TX, PORT_PCR_FSEL);
    CLEAR_BIT(M0P_PORT->MODEM_USART_RX, PORT_PCR_FSEL);

    /* USART configure */
    WRITE_REG(MODEM_USART->CR1, 0x80000000UL);
    WRITE_REG(MODEM_USART->DR,  0UL);
    WRITE_REG(MODEM_USART->BRR, 0xFF00UL);
    /* Disable USART Clock. */
    SET_BIT(M0P_CMU->FCG, MODEM_USART_CLK);
#elif defined(HC32F160)
    /* USART Port configure */
    CLEAR_BIT(CM_GPIO->MODEM_USART_TX, GPIO_PCR_FSEL);
    CLEAR_BIT(CM_GPIO->MODEM_USART_RX, GPIO_PCR_FSEL);

    /* USART configure */
    WRITE_REG(MODEM_USART->CR1, 0x80000000UL);
    WRITE_REG(MODEM_USART->DR,  0UL);
    WRITE_REG(MODEM_USART->BRR, 0xFF00UL);
    /* Disable USART Clock. */
    SET_BIT(CM_CMU->FCG, MODEM_USART_CLK);
#elif defined(HC32F4A0)
    /* USART Port configure */
    CLEAR_BIT(M4_GPIO->MODEM_USART_TX, GPIO_PFSR_FSEL);
    CLEAR_BIT(M4_GPIO->MODEM_USART_RX, GPIO_PFSR_FSEL);

    /* USART configure */
    WRITE_REG(MODEM_USART->CR1, 0x80000000UL);
    WRITE_REG(MODEM_USART->DR,  0x01FFUL);
    WRITE_REG(MODEM_USART->BRR, 0xFFFFUL);
    /* Disable USART Clock. */
    SET_BIT(M4_PWC->FCG3, MODEM_USART_CLK);
#elif defined(HC32M423)
    /* USART Port configure */
    CLEAR_BIT(CM_GPIO->MODEM_USART_TX, GPIO_PFSR_FSEL);
    CLEAR_BIT(CM_GPIO->MODEM_USART_RX, GPIO_PFSR_FSEL);

    /* USART configure */
    WRITE_REG(MODEM_USART->CR1, 0x80000000UL);
    WRITE_REG(MODEM_USART->DR,  0x01FFUL);
    WRITE_REG(MODEM_USART->BRR, 0x0000FF00UL);
    /* Disable USART Clock. */
    SET_BIT(CM_CMU->FCG, MODEM_USART_CLK);
#endif
}

/**
 * @brief  COM Initialize
 * @param  None
 * @retval None
 */
void COM_Init(void)
{
#if defined(HC32F460)
    /* USART Port configure */
    MODIFY_REG(M4_PORT->MODEM_USART_TX, PORT_PFSR_FSEL, MODEM_USART_TX_FUNC);
    MODIFY_REG(M4_PORT->MODEM_USART_RX, PORT_PFSR_FSEL, MODEM_USART_RX_FUNC);

    /* Enable USART Clock. */
    CLEAR_BIT(M4_MSTP->FCG1, MODEM_USART_CLK);
    /* Disbale TX/RX && clear interrupt flag */
    WRITE_REG(MODEM_USART->CR1, USART_CLEAN_FLAG_MASK);
    WRITE_REG(MODEM_USART->CR1, (USART_CR1_OVER8 | USART_CR1_FBME | USART_CR1_SBS));
    WRITE_REG(MODEM_USART->BRR, USART_BRR_CONFIG);
    /* USART polling send and receive data */
    SET_BIT(MODEM_USART->CR1, (USART_CR1_TE | USART_CR1_RE));
#elif defined(HC32F120) || defined(HC32M120)
    /* USART Port configure */
    MODIFY_REG(M0P_PORT->MODEM_USART_TX, PORT_PCR_FSEL, MODEM_USART_TX_FUNC);
    MODIFY_REG(M0P_PORT->MODEM_USART_RX, PORT_PCR_FSEL, MODEM_USART_RX_FUNC);

    /* Enable USART Clock. */
    CLEAR_BIT(M0P_CMU->FCG, MODEM_USART_CLK);
    /* Disbale TX/RX && clear interrupt flag */
    WRITE_REG(MODEM_USART->CR1, USART_CLEAN_FLAG_MASK);
    WRITE_REG(MODEM_USART->CR1, (USART_CR1_OVER8 | USART_CR1_SBS));
    WRITE_REG(MODEM_USART->BRR, USART_BRR_CONFIG);
    /* USART polling send and receive data */
    SET_BIT(MODEM_USART->CR1, (USART_CR1_TE | USART_CR1_RE));
#elif defined(HC32F160)
    /* USART Port configure */
    MODIFY_REG(CM_GPIO->MODEM_USART_TX, GPIO_PCR_FSEL, MODEM_USART_TX_FUNC);
    MODIFY_REG(CM_GPIO->MODEM_USART_RX, GPIO_PCR_FSEL, MODEM_USART_RX_FUNC);

    /* Enable USART Clock. */
    CLEAR_BIT(CM_CMU->FCG, MODEM_USART_CLK);
    /* Disbale TX/RX && clear interrupt flag */
    WRITE_REG(MODEM_USART->CR1, USART_CLEAN_FLAG_MASK);
    WRITE_REG(MODEM_USART->CR1, (USART_CR1_OVER8 | USART_CR1_SBS));
    WRITE_REG(MODEM_USART->BRR, USART_BRR_CONFIG);
    /* USART polling send and receive data */
    SET_BIT(MODEM_USART->CR1, (USART_CR1_TE | USART_CR1_RE));
#elif defined(HC32F4A0)
    /* USART Port configure */
    MODIFY_REG(M4_GPIO->MODEM_USART_TX, GPIO_PFSR_FSEL, MODEM_USART_TX_FUNC);
    MODIFY_REG(M4_GPIO->MODEM_USART_RX, GPIO_PFSR_FSEL, MODEM_USART_RX_FUNC);

    /* Enable USART Clock. */
    CLEAR_BIT(M4_PWC->FCG3, MODEM_USART_CLK);
    /* Disbale TX/RX && clear interrupt flag */
    WRITE_REG(MODEM_USART->CR1, USART_CLEAN_FLAG_MASK);
    WRITE_REG(MODEM_USART->CR1, (USART_CR1_OVER8 | USART_CR1_FBME | USART_CR1_SBS));
    WRITE_REG(MODEM_USART->BRR, USART_BRR_CONFIG);
    /* USART polling send and receive data */
    SET_BIT(MODEM_USART->CR1, (USART_CR1_TE | USART_CR1_RE));
#elif defined(HC32M423)
    /* USART Port configure */
    MODIFY_REG(CM_GPIO->MODEM_USART_TX, GPIO_PFSR_FSEL, MODEM_USART_TX_FUNC);
    MODIFY_REG(CM_GPIO->MODEM_USART_RX, GPIO_PFSR_FSEL, MODEM_USART_RX_FUNC);

    /* Enable USART Clock. */
    CLEAR_BIT(CM_CMU->FCG, MODEM_USART_CLK);
    /* Disbale TX/RX && clear interrupt flag */
    WRITE_REG(MODEM_USART->CR1, USART_CLEAN_FLAG_MASK);
    WRITE_REG(MODEM_USART->CR1, (USART_CR1_OVER8 | USART_CR1_SBS));
    WRITE_REG(MODEM_USART->BRR, USART_BRR_CONFIG);
    /* USART polling send and receive data */
    SET_BIT(MODEM_USART->CR1, (USART_CR1_TE | USART_CR1_RE));
#endif
}

/**
 * @brief  COM send data.
 * @param  [in] u8TxBuff                Pointer to the buffer to be sent.
 * @param  [in] u16Length               Send buffer length.
 * @retval None
 */
void COM_SendData(uint8_t *u8TxBuff, uint16_t u16Length)
{
    while ((u16Length--) > 0U)
    {
        USART_SendByte(*u8TxBuff);
        u8TxBuff++;
    }
}

/**
 * @brief  COM receive data.
 * @param  [out] u8RxBuff               Pointer to the buffer to be sent.
 * @param  [in]  u16Length              Receive data length.
 * @param  [in]  u32Timeout             Receive timeout(ms).
 * @retval An en_result_t enumeration value:
 *           - Ok: Receive data finished
 *           - Error: COM runtime error
 */
en_result_t COM_RecvData(uint8_t *u8RxBuff, uint16_t u16Length, uint32_t u32Timeout)
{
    uint8_t u8Temp;
    en_result_t enRet;
    uint16_t u16Cnt;
    uint32_t u32TickStart;
    uint32_t u32NewTick;
    uint32_t u32DelayVal;

    if ((NULL == u8RxBuff) || (0U == u16Length))
    {
        return Error;
    }

    for (u16Cnt=0U; u16Cnt < u16Length; u16Cnt++)
    {
        u32TickStart = SysTick_GetTick();
        do
        {
            enRet = USART_RecvByte(&u8Temp);
            if (Ok == enRet)
            {
                u8RxBuff[u16Cnt] = u8Temp;
                break;
            }
            u32NewTick  = SysTick_GetTick();
            u32DelayVal = (u32NewTick > u32TickStart) ? (u32NewTick - u32TickStart) : (TICK_RELOAD_VALUE - u32TickStart + 1U + u32NewTick);
        } while(u32DelayVal < u32Timeout);

        if (enRet != Ok)
        {
            return Error;
        }
    }

    return Ok;
}

/**
 * @}
 */

/**
 * @}
 */

/**
* @}
*/

/******************************************************************************
 * EOF (not truncated)
 *****************************************************************************/
